#ifndef __C_DRV_HD_H__
#define __C_DRV_HD_H__

#include "block.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef unsigned short __u16;
typedef unsigned int __u32;

typedef struct ide_identify_data
{
	__u16	general_cfg;					// 00    : general configuration
	__u16	num_cylinders;					// 01    : number of cylinders (default CHS trans)
	__u16	reserved0;						// 02    : reserved
	__u16	num_heads;						// 03    : number of heads (default CHS trans)
	__u16	num_bytes_per_track;			// 04    : number of unformatted bytes per track
	__u16	num_bytes_per_sector;			// 05    : number of unformatted bytes per sector
	__u16	num_sectors_per_track;			// 06    : number of sectors per track (default CHS trans)
	__u32	num_sector_per_card;			// 07-08 : number of sectors per card
	__u16	reserved1;						// 09    : reserved
	char	serial_str[20];					// 10-19 : serial number (string)
	__u16	buf_type;						// 20    : buffer type (dual ported)
	__u16	buf_size;						// 21    : buffer size in 512 increments
	__u16	num_ecc_bytes;					// 22    : number of ECC bytes passed on R/W Long cmds
	char	firmware_rev_str[8];			// 23-26 : firmware revision (string)
	char	model_num_str[40];				// 27-46 : model number (string)
	__u16	sectors_rw_multicmd;			// 47    : max number of sectors on R/W multiple cmds
	__u16	usedmovsd;						// 48    : Can use double word read/write?
	__u16	capabilities;					// 49    : LBA, DMA, IORDY support indicator
	__u16	reserved3;						// 50    : reserved
	__u16	pio_transfer_cyc_timing;		// 51    : PIO data transfer cycle timing mode
	__u16	dma_transfer_cyc_timing;		// 52    : single word DMA data transfer cycle timing mode
	__u16	curr_field_validity;			// 53    : words 54-58 validity (0 == not valid)
	__u16	num_curr_cylinders;				// 54    : number of current cylinders
	__u16	num_curr_heads;					// 55    : number of current heads
	__u16	num_curr_sectors_per_track;		// 56    : number of current sectors per track
	__u32	num_curr_capacity_in_sectors;	// 57-58 : current capacity in sectors
	__u16	muli_sector_setting;			// 59    : multiple sector setting
	__u32	lba_total_sectors;				// 60-61 : total sectors in LBA mode
	__u16	single_word_dma_support;		// 62    : single word DMA support
	__u16	multi_word_dma_support;			// 63    : multi word DMA support
	__u16	adv_pio_trans_mode_support;		// 64    : advanced PIO transfer mode supported
	__u16	min_multiword_dma_trans_cyc;	// 65    : minimum multiword DMA transfer cycle
	__u16	recommended_multiword_dma_cyc;	// 66    : recommended multiword DMA cycle
	__u16	min_pio_trans_time;				// 67    : min PIO transfer time without flow control
	__u16	min_pio_trans_time_with_iordy;	// 68    : min PIO transfer time with IORDY flow control
	__u16	reserved4[6];					// 69-74 : ATA reserved
	__u16	queue_depth;					// 75	 : queue depth
	__u16	reserved5[4];					// 76-79 : ATA reserved
	__u16	major_ver_num;					// 80	 : major version number
	__u16	minor_ver_num;					// 81	 : minor version number
	__u32	cmd_sets_supported;				// 82-83 : command sets supported
	__u16	cmd_sets_support_ext;			// 84	 : command sets support extension
	__u32	cmd_sets_enabled;				// 85-86 : command sets enabled
	__u16	cmd_sets_enable_ext;			// 87	 : command sets enable extension
	__u16	ultra_dma_support_cur_mode;		// 88	 : ultra DMA support and current mode
	__u16	security_erase_time;			// 89	 : security erase time
	__u16	enhanced_security_erase_time;	// 90	 : enhanced security erase time
	__u16	adv_pwr_mgr_value;				// 91	 : advanced power management value
	__u16	master_pswd_rev_code;			// 92	 : master password reversion code
	__u16	hardware_reset_value;			// 93	 : hardware reset value
	__u16	auto_acoustic_mgr_setting;		// 94	 : auto acoustic management setting
	__u16	reserved6[5];					// 95-99 : reserved
	unsigned long long lba48_total_sectors;	// 100-103: uint64_t contain the total number of 48 bit addressable sectors
	__u16	reserved7[24];					// 104-127: reserved
	__u16	dev_lock_func;					// 128   : Device lock function
	__u16	cur_set_features_options;		// 129   : Current set features options
}
PACKED ide_identify_data_t;

// 00: ata_device
#define IDE_GENERAL_CFG_ATA_DEVICE				(1 << 15)

// 49    : LBA, DMA, IORDY support indicator
#define IDE_CAPABILITIES_DMA_SUPPORTED			(1 << 8)

// 63: multi word DMA support
#define IDE_MULTIWORD_DMA_MODE_0_SUPPORTED		(1)
#define IDE_MULTIWORD_DMA_MODE_1_SUPPORTED		(1)
#define IDE_MULTIWORD_DMA_MODE_2_SUPPORTED		(2)
#define IDE_MULTIWORD_DMA_MODE_0_ACTIVE			(256)
#define IDE_MULTIWORD_DMA_MODE_1_ACTIVE			(512)
#define IDE_MULTIWORD_DMA_MODE_2_ACTIVE			(1024)

// 82-83 : command sets supported
#define IDE_CMD_SET_48BIT_LBA_SUPPORTED			(1 << 26)

// 88: ultra DMA support and current mode
#define IDE_ULTRA_DMA_MODE_0_SUPPORTED			(1)
#define IDE_ULTRA_DMA_MODE_1_SUPPORTED			(2)
#define IDE_ULTRA_DMA_MODE_2_SUPPORTED			(4)
#define IDE_ULTRA_DMA_MODE_3_SUPPORTED			(8)
#define IDE_ULTRA_DMA_MODE_4_SUPPORTED			(16)
#define IDE_ULTRA_DMA_MODE_5_SUPPORTED			(32)
#define IDE_ULTRA_DMA_MODE_6_SUPPORTED			(64)
#define IDE_ULTRA_DMA_MODE_0_ACTIVE				(256)
#define IDE_ULTRA_DMA_MODE_1_ACTIVE				(512)
#define IDE_ULTRA_DMA_MODE_2_ACTIVE				(1024)
#define IDE_ULTRA_DMA_MODE_3_ACTIVE				(2048)
#define IDE_ULTRA_DMA_MODE_4_ACTIVE				(4096)
#define IDE_ULTRA_DMA_MODE_5_ACTIVE				(4096)
#define IDE_ULTRA_DMA_MODE_6_ACTIVE				(4096)

// 129: Current set features options
#define IDE_CUR_SET_FEATURES_OPT_WRITE_CACHE		(1)
#define IDE_CUR_SET_FEATURES_OPT_READ_LOCK_AHEAD	(2)
#define IDE_CUR_SET_FEATURES_OPT_REVERTING			(4)
#define IDE_CUR_SET_FEATURES_OPT_AUTO_REASSIGN		(8)

// ATA status
#define ATA_SR_BSY			(0x80)			// Busy
#define ATA_SR_DRDY			(0x40)			// Drive ready
#define ATA_SR_DF			(0x20)			// Drive write fault
#define ATA_SR_DSC			(0x10)			// Drive seek complete
#define ATA_SR_DRQ			(0x08)			// Data request ready
#define ATA_SR_CORR			(0x04)			// Corrected data
#define ATA_SR_IDX			(0x02)			// Inlex
#define ATA_SR_ERR			(0x01)			// Error

// ATA error
#define ATA_ER_BBK			(0x80)			// Bad sector
#define ATA_ER_UNC			(0x40)			// Uncorrectable data
#define ATA_ER_MC			(0x20)			// No media
#define ATA_ER_IDNF			(0x10)			// ID mark not found
#define ATA_ER_MCR			(0x08)			// No media
#define ATA_ER_ABRT			(0x04)			// Command aborted
#define ATA_ER_TK0NF		(0x02)			// Track 0 not found
#define ATA_ER_AMNF			(0x01)			// No address mark

// ATA commands
#define ATA_CMD_READ_PIO				(0x20)
#define ATA_CMD_READ_PIO_EXT			(0x24)
#define ATA_CMD_MULTIREAD_PIO			(0xC4)
#define ATA_CMD_MULTIREAD_PIO_EXT		(0x29)
#define ATA_CMD_SET_MULTIPLE_MODE		(0xC6)
#define ATA_CMD_READ_DMA				(0xC8)
#define ATA_CMD_READ_DMA_EXT			(0x25)
#define ATA_CMD_WRITE_PIO				(0x30)
#define ATA_CMD_WRITE_PIO_EXT			(0x34)
#define ATA_CMD_WRITE_DMA				(0xCA)
#define ATA_CMD_WRITE_DMA_EXT			(0x35)
#define ATA_CMD_CACHE_FLUSH				(0xE7)
#define ATA_CMD_CACHE_FLUSH_EXT			(0xEA)
#define ATA_CMD_PACKET					(0xA0)
#define ATA_CMD_IDENTIFY_PACKET			(0xA1)
#define ATA_CMD_IDENTIFY				(0xEC)
#define ATA_CMD_SET_FEATURES			(0xEF)

#define IDE_ATA        					(0x00)
#define IDE_ATAPI						(0x01)
 
#define ATA_MASTER						(0x00)
#define ATA_SLAVE						(0x01)

// Channels:
#define ATA_PRIMARY						(0x00)
#define ATA_SECONDARY					(0x01)

#define ATA_REG_DATA					(0x00)
#define ATA_REG_ERROR					(0x01)
#define ATA_REG_FEATURES				(0x01)
#define ATA_REG_SECCOUNT0				(0x02)
#define ATA_REG_LBA0					(0x03)
#define ATA_REG_LBA1					(0x04)		// command block + 4
#define ATA_REG_LBA2					(0x05)		// command block + 5
#define ATA_REG_HDDEVSEL				(0x06)		// command block + 6
#define ATA_REG_COMMAND					(0x07)		// command block + 7
#define ATA_REG_STATUS					(0x07)		// command block + 7
#define ATA_REG_SECCOUNT1				(0x08)
#define ATA_REG_LBA3					(0x09)
#define ATA_REG_LBA4					(0x0A)
#define ATA_REG_LBA5					(0x0B)
#define ATA_REG_CONTROL					(0x02)		// control_block + 2
#define ATA_REG_ALTSTATUS				(0x02)		// control_block + 2
#define ATA_REG_DEVADDRESS				(0x0D)

#define PCI_IDE_COMMAND_REG				(0x04)		// word: R/W
#define PCI_IDE_CFG_BAR0_OFFSET			(0x10)		// dword: R/W
#define PCI_IDE_CFG_BAR4_OFFSET			(0x20)		// dword: R/W
#define PCI_IDE_TIMING_REG1				(0x40)		// word
#define PCI_IDE_TIMING_REG2				(0x42)		// word
#define PCI_IDE_2RD_IDETIMING_REG		(0x44)		// byte
#define PCI_IDE_UDMA_CTRL_REG			(0x48)		// byte
#define PCI_IDE_UDMA_TIMING_REG			(0x4A)		// word
#define PCI_IDE_IO_CONF_REG				(0x54)		// word

// set feature command
#define ATA_SF_SUBCMD_SET_TRANSFER_MODE		(0x03)
#define ATA_SF_SUBCMD_TRANSFER_MODE_PIO		(0)
#define ATA_SF_SUBCMD_TRANSFER_MODE_DMA		(0x20)
#define ATA_SF_SUBCMD_TRANSFER_MODE_UDMA	(0x40)

#define ATA_SF_ENABLE_WCACHE	(0x02)  // Enable write caching
#define ATA_SF_ENABLE_RLA		(0xAA)  // Enable read-lookahead

// drive information
#define ATA_DRIVE_AVAILABLE					(1)
#define ATA_DRIVE_LBA_SUPPORTED				(2)
#define ATA_DRIVE_LBA48_SUPPORTED			(4)
#define ATA_DRIVE_USE_PIO_32BITS			(8)
#define ATA_DRIVE_DOWNGRADE_PIO_MODE		(16)

// Bus master registers
#define BM_COMMAND_REG			(0)      // Offset to command reg
#define BM_STATUS_REG			(2)      // Offset to status reg
#define BM_PRD_ADDR				(4)      // Offset to PRD addr reg

// Bus master command register flags
#define BM_CR_STOP				(0x00)   // Stop transfer
#define BM_CR_START				(0x01)   // Start transfer
#define BM_CR_READ				(0x00)   // Read from memory
#define BM_CR_WRITE				(0x08)   // Write to memory

// Bus master status register flags
#define BM_SR_ACT				(0x01)   // Active
#define BM_SR_ERR				(0x02)   // Error
#define BM_SR_INT				(0x04)   // INTRQ signal asserted
#define BM_SR_DRV0				(0x20)   // Drive 0 can do dma
#define BM_SR_DRV1				(0x40)   // Drive 1 can do dma
#define BM_SR_SIMPLEX			(0x80)   // Simplex only

#define ATA_DEVSEL_FLAG_LBA		(0x40)

// physical region descriptor
#define ATA_PRD_FLAG_EOT		(0x8000)

// this flag is set when the phy_addr in PRD has been
// transformed to virtual address
// this is happen in POI access mode
#define ATA_RPD_FLAG_VIRT_ADDR	(0x4000)

typedef struct ata_prd
{
	uint phy_base_addr;
	ushort count;			// count of bytes, max = 0 (= 65536)
	ushort flags;
}
PACKED ata_prd_t;

#define ATA_MAX_PRD_CNT			(PAGE_SZ / sizeof(ata_prd_t))

struct ata_drive_info
{
	uint flags;
	
	// total sectors
	union {
		unsigned long long total_sectors;
		struct {
			unsigned short cyls;
			unsigned short heads;
			unsigned short sectors;
		} chs;
	} ts;

	uint multisect;
	char dma_support_mode;
	char dma_active_mode;
	char udma_support_mode;
	char udma_active_mode;

	// elevator request list
	listnode_t req_queue;
};

#define IDE_CHNL_SM_DRIVE_UNKNOWN		(0)
#define IDE_CHNL_SM_ACCESS_UNKNOWN		(0)
#define IDE_CHNL_SM_ACCESS_READ			(DEV_BLK_NODE_FLAG_ACCESS_READ)
#define IDE_CHNL_SM_ACCESS_WRITE		(DEV_BLK_NODE_FLAG_ACCESS_WRITE)

#define IDE_CHNL_SM_STAT_READY			(0)
#define IDE_CHNL_SM_STAT_PREPARING		(1)
#define IDE_CHNL_SM_STAT_EXECUTING		(2)
#define IDE_CHNL_SM_STAT_FINALIZING		(3)

#define ide_sm_drive_idx(ch)	(channels[ch].sm.drive - 1)

#define IDE_CHNL_SM_MAX_RETRIES_CNT		(160)

struct ide_channel_state
{
	// 0 - unknown
	// 1 - drive 0
	// 2 - drive 1
	uint drive : 2;

	// access type:
	// 0 - unknown
	// 1 - read
	// 2 - write
	uint access : 2;

	// current state
	// 0 - ready
	// 1 - preparing
	// 2 - executing
	// 3 - finalizing
	uint state : 4;

	// if we are in a retry mode
	uint is_retry : 1;

	// how many times we've retried
	uint retry_count : 8;

	// total blocks to be handle
	uint blocks;

	// the start block id
	unsigned long long blkid;

	dev_blk_reqlist_t* reqlst;

	// spinlock
	spinlock_t spinlock;
};

typedef struct ide_channel
{
	uint io_base;							// io base
	uint ctrl_base;							// control base
	uint bmide;								// bus master ide

	// PRDT
	ata_prd_t* prdt;
	uint prdt_page_idx;
	uint prdt_next_prd;

	// state machine
	struct ide_channel_state sm;

	// drive information
	struct ata_drive_info drvinfo[2];
}
ide_channel_t;

#define ATA_CHNL_CUR_PRD_IDX(ch)		(channels[ch].prdt_next_prd - 1)
#define ATA_CHNL_CUR_PRD(ch)			(&channels[ch].prdt[ATA_CHNL_CUR_PRD_IDX(ch)])
#define ATA_PRD_VALID(ch, prd)			((prd) >= channels[ch].prdt && ((uint)(prd)) < (((uint)channels[ch].prdt) + PAGE_SZ))


#define ide_cmd_block_write(channel, reg, data)	\
	outb((data), channels[channel].io_base + (reg))

#define ide_ctrl_block_write(channel, reg, data)	\
	outb((data), channels[channel].ctrl_base + (reg))

#define ide_cmd_block_read(channel, reg)	inb(channels[channel].io_base + (reg))
#define ide_ctrl_block_read(channel, reg)	inb(channels[channel].ctrl_base + (reg))

#define IDE_SECTOR_SIZE			(512)

// ----------------------------------------------------
// Elevator Algorithm definition
// ----------------------------------------------------

// shall be less than 65536
#define IDE_ELEVATOR_ROUND_MAX_SECTOR		(16384)

typedef struct ide_elevator_round
{
	listnode_t ownerlist;
	uint remain_blk_cnt;
}
ide_elevator_round_t;

#ifdef __cplusplus
}
#endif
#endif
/* EOF */
